﻿using Nest;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace ESApi.ElasticSearch
{
    public class ESHelper
    {
        private static ConnectionSettings settings = new ConnectionSettings(new Uri("http://localhost:9200")).DefaultIndex("articles");

        private static ElasticClient client = new ElasticClient(settings);

        /// <summary>
        /// 获取client
        /// </summary>
        /// <returns></returns>
        public static ElasticClient GetClient()
        {
            return client;
        }
        /// <summary>
        /// 创建映射
        /// </summary>
        /// <returns></returns>
        public static bool CreateMapping()
        {
            try
            {
                //映射
                CreateIndexResponse createIndexResponse = client.Indices.Create("articles", c => c.Map<Article>(m => m.AutoMap()));
                return true;
            }
            catch (Exception ex)
            {
                return false;
            }
        }

        /// <summary>
        /// 创建单个文档
        /// </summary>
        /// <param name="client"></param>
        /// <param name="article"></param>
        /// <returns></returns>
        public static dynamic CreateArticle(Article article)
        {
            var indexResponse = client.IndexDocument<Article>(article);
            return new { flag = true, msg = "操作成功" };
        }

        /// <summary>
        /// 批量新增
        /// </summary>
        /// <param name="client"></param>
        /// <param name="list"></param>
        /// <returns></returns>
        public static dynamic CreateBulk(List<Article> list)
        {

            var bulkAllObservable = client.BulkAll(list, b => b
                                .Index("articles")
                                .BackOffTime("30s")
                                .BackOffRetries(2)
                                .RefreshOnCompleted()
                                .MaxDegreeOfParallelism(Environment.ProcessorCount)
                                .Size(1000)
                                    )
                                .Wait(TimeSpan.FromMinutes(15), next =>
                                {
                                    // do something e.g. write number of pages to console
                                });
            return new { flag = true, msg = "操作成功" };
        }
        /// <summary>
        /// 根据id查询
        /// </summary>
        /// <param name="ids"></param>
        /// <returns></returns>
        public static List<Article> GetByIds(List<long> ids)
        {
            var searchResponse = client.Search<Article>(s => s.Query(q => q.Ids(m => m.Values(ids))));
            return searchResponse.Documents.ToList();

        }

        /// <summary>
        /// 批量删除
        /// </summary>
        /// <param name="client"></param>
        /// <param name="list"></param>
        /// <returns></returns>
        public static dynamic DeleteBulk(List<Article> list)
        {
            var bulkResponse = client.DeleteMany(list);
            return new { flag = true, msg = "操作成功" };
        }
        /// <summary>
        /// 全文检索
        /// </summary>
        /// <param name="page"></param>
        /// <param name="keyword"></param>
        /// <returns></returns>
        public static Dictionary<string, object> Search(int page, string keyword)
        {
            try
            {
                int size = 10;
                int from = (page - 1) * size;
                var searchResponse = client.Search<Article>(s => s
                                          .From(from)
                                          .Size(size)
                                          .Query(q =>
                                          q.MultiMatch(c => c
                                                .Fields(f => f.Field(a => a.Title, 10).Field(a => a.Content).Field(a => a.Company, 10))
                                                .Operator(Operator.Or)//只要有一个词在文档中出现都可以
                                                .MinimumShouldMatch(new MinimumShouldMatch("50%"))
                                                .Query(keyword)
                                            ))
                                             .Highlight(h => h
                                            .PreTags("<span style='color:red;'>")
                                            .PostTags("</span>")
                                            .FragmentSize(100)
                                            .NoMatchSize(150)
                                            .Fields(
                                                fs => fs
                                                    .Field(p => p.Title),
                                                 fs => fs
                                                    .Field(p => p.Company),
                                                fs => fs
                                                     .Field(p => p.Content)
                                            )
                                          )
                                      );

                var hits = searchResponse.HitsMetadata.Hits;
                var total = searchResponse.Total;

                foreach (var hit in hits)
                {
                    foreach (var highlightField in hit.Highlight)
                    {
                        if (highlightField.Key == "title")
                        {
                            foreach (var highlight in highlightField.Value)
                            {
                                hit.Source.Title = highlight.ToString();
                            }
                        }

                        if (highlightField.Key == "content")
                        {
                            foreach (var highlight in highlightField.Value)
                            {
                                hit.Source.Content = highlight.ToString();
                            }
                        }

                        if (highlightField.Key == "company")
                        {
                            foreach (var highlight in highlightField.Value)
                            {
                                hit.Source.Company = highlight.ToString();
                            }
                        }
                    }
                }
                var hitsJson = Newtonsoft.Json.JsonConvert.SerializeObject(hits);

                List<Article> list = new List<Article>();
                foreach (var item in hits)
                {
                    list.Add(item.Source);
                }
                Dictionary<string, object> result = new Dictionary<string, object>();
                result.Add("list", list);
                result.Add("total", total);

                return result;

            }
            catch (Exception ex)
            {

                throw;
            }
        }
    }

    [ElasticsearchType(RelationName = "articles")]
    public class Article
    {
        /// <summary>
        /// id
        /// </summary>
        [Number]
        public long Id { get; set; }
        /// <summary>
        /// 标题
        /// </summary>
        [Text(Analyzer = "ik_max_word", Index = true)]
        public string Title { get; set; }
        /// <summary>
        /// 类型 新闻还是招聘
        /// </summary>
        [Keyword]
        public string Type { get; set; }
        /// <summary>
        /// 内容
        /// </summary>
        [Text(Analyzer = "ik_max_word", Index = true)]
        public string Content { get; set; }
        /// <summary>
        /// 新闻作者
        /// </summary>
        [Keyword]
        public string Author { get; set; }
        /// <summary>
        /// 招聘公司
        /// </summary>
        [Text(Analyzer = "ik_max_word", Index = true)]
        public string Company { get; set; }
        /// <summary>
        /// 招聘公司地址
        /// </summary>
        [Text(Analyzer = "ik_max_word", Index = true)]
        public string CompanyAddress { get; set; }
        /// <summary>
        /// 创建时间
        /// </summary>
        [Date]
        public DateTime CreateTime { get; set; }
        /// <summary>
        /// 访问路径
        /// </summary>
        [Keyword]
        public string WebPath { get; set; }
    }
}